[Linux]05 shell 脚本语法

入门、sed命令  替换、awk命令 取数、分割、循环、if判断、数组、传递参数、变量、shell的debug

Posted by 李玉坤 on 2018-03-04

入门

  1. shell脚本默认的【大家约定的并不是百分百】是.sh结尾的
  2. 而且脚本需要有执行权限+x
  3. 我们也可以通过sh [文件名] 来执行本文件;也是用sh命令来执行这个脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[hadoop@hadoop data]$ sh --help
GNU bash, version 4.2.46(2)-release-(x86_64-redhat-linux-gnu)
Usage: sh [GNU long option] [option] ...
sh [GNU long option] [option] script-file ...
GNU long options:
--debug
--debugger
--dump-po-strings
--dump-strings
--help
--init-file
--login
--noediting
--noprofile
--norc
--posix
--protected
--rcfile
--rpm-requires
--restricted
--verbose
--version
Shell options:
-irsD or -c command or -O shopt_option (invocation only)
-abefhkmnptuvxBCHP or -o option
Type `sh -c "help set"' for more information about shell options.
Type `sh -c help' for more information about shell builtin commands.

总结:
1.后缀是.sh
2.第一行的#!/bin/bash

假如使用sh命令执行脚本文件,可以没有+x 和 第一行解释器#!/bin/bash
假如不是使用sh命令,那么需要+x 且 #!/bin/bash

shell的debug

可以在#!/bin/bash 加上 -x
即 #!/bin/bash -x
来执行debuy 从上而下 一行行执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[hadoop@hadoop data]$ vim test.sh
[hadoop@hadoop data]$ cat test.sh
#!/bin/bash -x
echo "hello world"
ll
pwd
[hadoop@hadoop data]$ chmod +x test.sh
[hadoop@hadoop data]$ ./test.sh
+ echo 'hello world'
hello world
+ ll
./test.sh: line 3: ll: command not found
+ pwd
/home/hadoop/data
[hadoop@hadoop data]$

变量

1
2
3
4
5
6
7
8
9
10
11
[hadoop@hadoop data]$ ./test.sh 
hello world
Thu Apr 11 19:03:19 CST 2019
[hadoop@hadoop data]$ cat test.sh
#!/bin/bash
WANG='hello world'
DATE=`date`

echo ${WANG}
echo ${DATE}
[hadoop@hadoop data]$

注意:变量全部用大写

静态变量 【可以没有引号;可以单引号和双引号】
K=V ‘V’ “V”

动态变量【反斜杠引号】【比如TEST=spark echo ${TEST}指的是用户环境里的spark命令】[建议使用用户环境变量里的命令时候补全命令的路径(也就是安装目录下的bin目录下的此命令=全路径)]
K=V

=前后不能有空格

引用:【可以有{}也可以没有{}中括号】
$KA 【这里的KA是一个变量】
${K}A 【这里的K是一个变量;A就是字母A】

传递参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[hadoop@hadoop data]$ cat test.sh
#!/bin/bash


echo $1
echo $2
echo "个数:$#"
echo "参数作为一个长字符串:$*"
echo "PID: $$"
[hadoop@hadoop data]$ ./test.sh


个数:0
参数作为一个长字符串:
PID: 10321
[hadoop@hadoop data]$
[hadoop@hadoop data]$ ./test.sh a b
a
b
个数:2
参数作为一个长字符串:a b
PID: 10324
[hadoop@hadoop data]$

个数:0
参数作为一个长字符串:
PID: 10321【shell脚本执行的那一刹那的pid;执行完毕后pid就消失了】

1、$1代表第一个参数
2、$2代表第二个参数
3、shell脚本传递参数按照空格来分割
4、$#代表的是参数的个数
5、$号代表把传递进来的参数作为长字符串输出

补充:PID: 10321如何确定已经消失

1
2
3
4
[hadoop@hadoop data]$ ps -ef|grep 10321
hadoop 10326 10162 0 19:18 pts/0 00:00:00 grep --color=auto 10321
[hadoop@hadoop data]$ ps -ef|grep 10321|grep -v grep
[hadoop@hadoop data]$

可以看出10321是没有进程存在的;因为脚本执行完毕后pid就会消失。
第一次输出的hadoop 10326 10162 0 19:18 pts/0 00:00:00 grep –color=auto 10321是捕获的自己执行的10321并不是pid为10321的进程;加上|grep -v grep就会忽略捕获自己

数组

shell脚本里的数组只支持一维的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[hadoop@hadoop data]$ cat test.sh
#!/bin/bash

arr=(dingyi zhaoer zhangsan lisi wangwu)

echo ${arr[@]}
echo ${arr[*]}
echo ${arr[4]}
echo ${#arr[@]}

[hadoop@hadoop data]$ ./test.sh
dingyi zhaoer zhangsan lisi wangwu
dingyi zhaoer zhangsan lisi wangwu
wangwu
5
[hadoop@hadoop data]$

1、数组以空格分割的
2、@和*表示输出数组中所有元素
3、[4]表示第五个元素
5、#arr[@]表示数组的元素个数

if判断

1
2
3
4
5
6
7
8
9
10
11
12
13
[hadoop@hadoop data]$ cat test.sh
#!/bin/bash
A="abc"
B="efgh"


if [ "${a}" == "$b" ];then
echo "=="
else
echo "!="
fi
[hadoop@hadoop data]$ ./test.sh
==​

这里的a,b都不存在所以都是空的;所以输出的是==

注意
==前后有空格
[ $a == $b ]

启用debug’模式查看并修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[hadoop@hadoop data]$ cat test.sh
#!/bin/bash -x
A="abc"
B="efgh"


if [ "${a}" == "$b" ];then
echo "=="
else
echo "!="
fi
[hadoop@hadoop data]$ ./test.sh
+ A=abc
+ B=efgh
+ '[' '' == '' ']'
+ echo ==
==
[hadoop@hadoop data]$
修改后
[hadoop@hadoop data]$ cat test.sh
#!/bin/bash
A="abc"
B="efgh"


if [ "${A}" == "$B" ];then
echo "=="
else
echo "!="
fi
[hadoop@hadoop data]$ ./test.sh
!=​

if elif else

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[hadoop@hadoop data]$ cat test.sh
#!/bin/bash
A="abc"
B="efgh"


if [ "${A}" == "$B" ];then
echo "=="
elif [ $A == "abc" ];then
echo "abc here"
else
echo "!="
fi
[hadoop@hadoop data]$ ./test.sh
abc here

循环

let表示后面的值要进行运算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
[hadoop@hadoop data]$ cat test.sh
#!/bin/bash

j=0
for x in 1 2 3 4 5
do
echo $x
let "j++"
done
echo $j
echo "------------------"

for ((i=1;i<5;i++))
do
echo $i
done
echo "===================="

x=1
y=1
while(($y<5))
do
echo $y
let "y++"
let "x++"
done
echo "x: ${x}"
[hadoop@hadoop data]$ ./test.sh
1
2
3
4
5
5
------------------
1
2
3
4
====================
1
2
3
4
x: 5
[hadoop@hadoop data]$

分割

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[hadoop@hadoop data]$ cat test.sh
#!/bin/bash

S="wangwu,zhangsan,lisi,dingyi"

OLD_IFS="$IFS"
IFS=","
arr=($S)
IFS="OLD_IFS"

for x in ${arr[*]}
do
echo $x
done
[hadoop@hadoop data]$ ./test.sh
wangwu
zhangsan
lisi
dingyi
[hadoop@hadoop data]$

其中

OLD_IFS=”$IFS”
IFS=”,”【分隔符】
arr=($S)【数组】
IFS=”OLD_IFS”

是固定写法;将分割好的元素放入arr数组

awk命令 取数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
[hadoop@hadoop data]$ cat test.txt 
1 2 3
4 5 6
7 8 9
打印第一列
[hadoop@hadoop data]$ cat test.txt |awk '{print $1}'
1
4
7
[hadoop@hadoop data]$
打印前两列
[hadoop@hadoop data]$ cat test.txt |awk '{print $1 $2}'
12
45
78
[hadoop@hadoop data]$ cat test.txt |awk '{print $1,$2}'
1 2
4 5
7 8

有分隔符的打印
[hadoop@hadoop data]$ cat test.txt
1,2,3
4,5,6
7,8,9
[hadoop@hadoop data]$
[hadoop@hadoop data]$ cat test.txt |awk '{print $2}'【后面这个单引号不可以是双引号】



[hadoop@hadoop data]$ cat test.txt |awk -F "," '{print $2}'
2
5
8
打印行
[hadoop@hadoop data]$ cat test.txt |awk -F "," 'NR==1'
1,2,3
[hadoop@hadoop data]$ cat test.txt |awk -F "," 'NR==3'
7,8,9
[hadoop@hadoop data]$ cat test.txt |awk -F "," 'NR>1'
4,5,6
7,8,9
[hadoop@hadoop data]$
打印大于第一行的行并第三列
[hadoop@hadoop data]$ cat test.txt |awk -F "," 'NR>1{ print $3 }'
6
9
[hadoop@hadoop data]$
同等
[hadoop@hadoop data]$ awk -F "," 'NR>1{ print $3 }' test.txt
6
9
[hadoop@hadoop data]$ awk --help 【具体看命令帮助】

其中{print $1}表示打印第一列;{print $2}就是第二列;{print $0}是打印全部;

注意{print $1,$2}和{print $1 $2}表示第一和第二列;有逗号和没逗号是有区别的

sed命令 替换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
[hadoop@hadoop data]$ vi test.log
a b c
1 2 3
替换a为aa
[hadoop@hadoop data]$ sed -i 's/a/aa/' test.log
[hadoop@hadoop data]$ cat test.log
aa b c
1 2 3


将aa替换为aa'
[hadoop@hadoop data]$ sed -i "s/aa/aa'/" test.log
[hadoop@hadoop data]$ cat test.log
aa' b c
1 2 3

将aa'替换为bbb【将/换为?用是一样的】
[hadoop@hadoop data]$ sed -i "s?aa'?bbb?" test.log
[hadoop@hadoop data]$ cat test.log
bbb b c
1 2 3



全局替换 g表示全局global
[hadoop@hadoop data]$ sed -i "s/b/w/g" test.log
[hadoop@hadoop data]$ cat test.log
www w c
1 2 3


每行的行首前面加uuu
[hadoop@hadoop data]$ sed -i "s/^/uuu&/g" test.log
[hadoop@hadoop data]$ cat test.log
uuuwww w c
uuu1 2 3


每行行尾后面加uuu
[hadoop@hadoop data]$ sed -i "s/$/&uuu/g" test.log

[hadoop@hadoop data]$ cat test.log
uuuwww w cuuu
uuu1 2 3uuu
[hadoop@hadoop data]$

补充

case in
判断uname是否是以CYGWIN*) 右括号结尾的

1
2
3
4
cygwin=false
case "$(uname)" in CYGWIN*)
cygwin=true;;
esac

-z
判断字符串长度是否为0

1
2
3
4
5
6
7
teacher="wuwang"
if [ -z "${teacher}" ]; then
echo "Jepson"
else {
echo ${teacher}
}
fi
1
2
3
home=`cd (dirname "$0");pwd`
echo ${home}
#结果是 当前目录

$@

1
2
3
4
5
6
7
function main() {
echo "input params is:"$@
}

main "$@"
#运行test.sh后面跟输入 xx yy zz
#输出结果 xx yy zz

exec
执行后面的语句

1
exec "${SPARK_HOME}"/bin/...